Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IPython integration 😎 #306

Open
wants to merge 1 commit into
base: ctx_result_consumption
Choose a base branch
from

Conversation

goodboy
Copy link
Owner

@goodboy goodboy commented Mar 20, 2022

Like it sounds, with more refinements to come!

This is a POC and seems to do about what I'd like; would appreciate lurker feedback 😉

ping @mikenerone, original author of the base gists for this:

TODO:

@goodboy goodboy added experiment Exploratory design and testing debugging labels Mar 20, 2022
@goodboy goodboy force-pushed the ctx_result_consumption branch from 2218e86 to 346cf6e Compare April 11, 2022 21:49
@goodboy goodboy force-pushed the ipython_integration branch from 2569815 to bbdf3d9 Compare April 11, 2022 21:50
@goodboy goodboy force-pushed the ctx_result_consumption branch from 346cf6e to 7facf38 Compare April 12, 2022 17:24
@goodboy goodboy force-pushed the ipython_integration branch from bbdf3d9 to 89240b9 Compare April 12, 2022 17:25
@goodboy goodboy force-pushed the ctx_result_consumption branch from 7facf38 to 4444fdf Compare April 17, 2022 17:16
@goodboy goodboy force-pushed the ipython_integration branch from 89240b9 to e8568b7 Compare April 17, 2022 17:18
@goodboy goodboy force-pushed the ctx_result_consumption branch from 4444fdf to 0b3590c Compare July 27, 2022 15:44
@goodboy goodboy removed the debugging label Aug 1, 2022
@goodboy goodboy force-pushed the ipython_integration branch from 658c760 to f378e69 Compare September 6, 2022 12:21
@goodboy goodboy force-pushed the ipython_integration branch 4 times, most recently from 329ea3b to 206a523 Compare September 16, 2022 03:50
@goodboy goodboy force-pushed the ipython_integration branch 2 times, most recently from d0106b8 to a5c6941 Compare October 12, 2022 17:09
@goodboy goodboy force-pushed the ctx_result_consumption branch from 0b3590c to b046cd3 Compare October 13, 2022 16:58
@goodboy goodboy mentioned this pull request Oct 27, 2022
8 tasks
@goodboy goodboy force-pushed the ctx_result_consumption branch from b046cd3 to f05364c Compare December 12, 2022 15:07
@goodboy goodboy force-pushed the ipython_integration branch from a5c6941 to 37ec037 Compare December 12, 2022 20:17
@goodboy goodboy force-pushed the ctx_result_consumption branch 2 times, most recently from 8b93a1b to 2fe9a1a Compare December 12, 2022 20:26
@goodboy goodboy force-pushed the ipython_integration branch 3 times, most recently from af47834 to 8c9f1c4 Compare December 13, 2022 20:20
@goodboy
Copy link
Owner Author

goodboy commented Jan 14, 2023

Turns out there might be a better solution for what we actually want (await <blah> inside any REPL, but mostly our debugger UX).


from @smurfix on gitter:

import trio
import greenback as gb
AW=gb.await_

async def wat():
    await trio.sleep(0.1)
    return "yes"

async def run():
    await gb.ensure_portal()
    breakpoint()
    pass

trio.run(run)

which can be called from repl like:

(Pdb) AW(wat())
'yes'

with follow up from @oremanj actually using pdb++ 💥 :

$ python3.8 -c "import trio, pdb, greenback; trio.run(greenback.with_portal_run_sync, lambda: breakpoint())"
(Pdb++) greenback.await_(trio.sleep(1))
<1sec delay>

also a further extended example 🏄🏼

$ python3.8 -c "import trio, greenback, code; trio.run(greenback.with_portal_run_sync, code.interact)"
>>> import trio
>>> from greenback import await_ as aw, async_context as acm
>>> async def task(interval, msg):
...   while True:
...     await trio.sleep(interval)
...     print(msg)
...
>>> with acm(trio.open_nursery()) as nursery:
...   nursery.start_soon(task, 2, "every two seconds")
...   nursery.start_soon(task, 0.75, "every 3/4 second")
...   aw(task(1.7, "every 1.7 seconds"))
...
every 3/4 second
every 3/4 second
every 1.7 seconds
every two seconds
every 3/4 second
every 3/4 second
every 1.7 seconds
every 3/4 second
every two seconds
^CTraceback (most recent call last):
  File "/usr/lib/python3.8/code.py", line 90, in runcode
    exec(code, self.locals)
  File "<console>", line 4, in <module>
  File "/usr/lib/python3.8/site-packages/greenback/_impl.py", line 653, in await_
    raise exception_from_greenbacked_function
  File "<console>", line 3, in task
  File "/usr/lib/python3.8/site-packages/trio/_timeouts.py", line 75, in sleep
    await sleep_until(trio.current_time() + seconds)
  File "/usr/lib/python3.8/site-packages/trio/_timeouts.py", line 56, in sleep_until
    await sleep_forever()
  File "/usr/lib/python3.8/site-packages/trio/_timeouts.py", line 40, in sleep_forever
    await trio.lowlevel.wait_task_rescheduled(lambda _: trio.lowlevel.Abort.SUCCEEDED)
  File "/usr/lib/python3.8/site-packages/trio/_core/_traps.py", line 166, in wait_task_rescheduled
    return (await _async_yield(WaitTaskRescheduled(abort_func))).unwrap()
  File "/usr/lib/python3.8/site-packages/outcome/_sync.py", line 111, in unwrap
    raise captured_error
  File "/usr/lib/python3.8/site-packages/trio/_core/_run.py", line 1178, in raise_cancel
    raise KeyboardInterrupt
KeyboardInterrupt
>>>

@smurfix
Copy link

smurfix commented Jan 15, 2023

To make this work anywhere we should teach Trio's task creation code to unconditionally create a Greenback portal in every new task; otherwise debugging at random breakpoints won't work.

@goodboy
Copy link
Owner Author

goodboy commented Jan 16, 2023

@smurfix agreed, this is already an issue with debugging single task crashes within a nursery as well.

Currently on a task crash, you can't breakpoint() at the (specific task's) error stack frame and instead always end up at the nursery exit; so, an extended nursery is needed for both of these cases:

  • handling task-level crashes with a breakpoint() and engaging the REPL in that task's frame,
  • overriding the global hook to always allow using await in the REPL (and obviously making the particular REPL plug-gable in the longer run)

Further, this probably plays best with the idea of a OCONursery (one-cancels-one) style nursery where every task has an associated individual cancel scope that can be managed independently of other tasks such that respawns can happen on a per-task-failure scenario.

@goodboy goodboy force-pushed the ipython_integration branch from 8c9f1c4 to 4b31973 Compare January 26, 2023 22:50
This code is originally written (with much thanks) by
@mikenerone:matrix.org. Adds a `tractor.trionics.ipython_embed()` which
is `trio` compatible and allows straight up `await async_func()` calls
in the REPL with expected default blocking semantics. More refinements
to come including user config loading and eventually a foundation for
what will be a console REPL + %magics for shipping work off to actor
clusters and manual respawn controls and thus probably eventually
obsoleting all the "parallel" stuff built into `ipython` B)

Probably pertains to #130
@goodboy goodboy force-pushed the ipython_integration branch from 4b31973 to 7f65d80 Compare January 30, 2023 19:08
@goodboy goodboy force-pushed the ctx_result_consumption branch from 2fe9a1a to 6120e99 Compare January 30, 2023 19:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
experiment Exploratory design and testing
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants